#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#include <imp/imp_audio.h>
#include <imp/imp_log.h>

#include "testopt.h"

#define TAG "test_ai"

#define IMP_AUDIO_BUF_SIZE (4 * (AEC_SAMPLE_RATE * sizeof(short) * AEC_SAMPLE_TIME / 1000))
#define IMP_AUDIO_RECORD_NUM 200

extern TEST_ARGS testArgs;   /*Save input param*/
extern char fileNameBuf[NAME_BUF_SIZE];

static char outFileName[256] = "test_ai.pcm";
static int  sampleRate = 16000;
static int  frmNum = 20;
static int  numPerFrm = 640;
static int  recordTime = 500;
static int  aiVol = 60;
static int  aiGain = 28;

static int  nsMode = 0;  /*ns mode of noise suppression*/
static int  nsFlag = 0;
static int  hpfFlag = 0;  /*enable hpf flag*/
static int  agcFlag = 0;  /*enable agc flag*/


IMPAudioAgcConfig agcConfig = {
			.TargetLevelDbfs = 0,
			.CompressionGaindB = 9
};

static void *ai_record_thread(void *argv)
{
	int ret = -1;
	int record_num = 0;

	FILE *record_file = fopen(outFileName, "wb");

	if(record_file == NULL) {
		IMP_LOG_ERR(TAG, "fopen %s failed\n", outFileName);
		return NULL;
	}

	/* Step 1: set public attribute of AI device. */
	int devID = 1;
	IMPAudioIOAttr attr;
	attr.samplerate = sampleRate;
	attr.bitwidth = AUDIO_BIT_WIDTH_16;
	attr.soundmode = AUDIO_SOUND_MODE_MONO;
	attr.frmNum = frmNum;
	attr.numPerFrm = numPerFrm;
	attr.chnCnt = 1;
	ret = IMP_AI_SetPubAttr(devID, &attr);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "set ai %d attr err: %d\n", devID, ret);
		return NULL;
	}

	memset(&attr, 0x0, sizeof(attr));
	ret = IMP_AI_GetPubAttr(devID, &attr);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "get ai %d attr err: %d\n", devID, ret);
		return NULL;
	}

	IMP_LOG_INFO(TAG, "Audio In GetPubAttr samplerate : %d\n", attr.samplerate);
	IMP_LOG_INFO(TAG, "Audio In GetPubAttr   bitwidth : %d\n", attr.bitwidth);
	IMP_LOG_INFO(TAG, "Audio In GetPubAttr  soundmode : %d\n", attr.soundmode);
	IMP_LOG_INFO(TAG, "Audio In GetPubAttr     frmNum : %d\n", attr.frmNum);
	IMP_LOG_INFO(TAG, "Audio In GetPubAttr  numPerFrm : %d\n", attr.numPerFrm);
	IMP_LOG_INFO(TAG, "Audio In GetPubAttr     chnCnt : %d\n", attr.chnCnt);

	/* Step 2: enable AI device. */
	ret = IMP_AI_Enable(devID);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "enable ai %d err\n", devID);
		return NULL;
	}

	/* Step 3: set audio channel attribute of AI device. */
	int chnID = 0;
	IMPAudioIChnParam chnParam;
	chnParam.usrFrmDepth = 20;
	ret = IMP_AI_SetChnParam(devID, chnID, &chnParam);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "set ai %d channel %d attr err: %d\n", devID, chnID, ret);
		return NULL;
	}

	memset(&chnParam, 0x0, sizeof(chnParam));
	ret = IMP_AI_GetChnParam(devID, chnID, &chnParam);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "get ai %d channel %d attr err: %d\n", devID, chnID, ret);
		return NULL;
	}

	IMP_LOG_INFO(TAG, "Audio In GetChnParam usrFrmDepth : %d\n", chnParam.usrFrmDepth);

	/* Step 4: enable AI channel. */
	ret = IMP_AI_EnableChn(devID, chnID);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "Audio Record enable channel failed\n");
		return NULL;
	}

	/* Step 5: Set audio channel volume. */
	int chnVol = aiVol;
	ret = IMP_AI_SetVol(devID, chnID, chnVol);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "Audio Record set volume failed\n");
		return NULL;
	}

	ret = IMP_AI_GetVol(devID, chnID, &chnVol);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "Audio Record get volume failed\n");
		return NULL;
	}
	IMP_LOG_INFO(TAG, "Audio In GetVol    vol : %d\n", chnVol);

	int aigain = aiGain;
	ret = IMP_AI_SetGain(devID, chnID, aigain);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "Audio Record Set Gain failed\n");
		return NULL;
	}

	ret = IMP_AI_GetGain(devID, chnID, &aigain);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "Audio Record Get Gain failed\n");
		return NULL;
	}
	IMP_LOG_INFO(TAG, "Audio In GetGain    gain : %d\n", aigain);

	if(1 == hpfFlag) {
		ret = IMP_AI_EnableHpf(&attr);
		if(ret != 0) {
			printf("enable audio hpf error.\n");
			IMP_LOG_INFO(TAG, "enable audio hpf error.\n");
			return NULL;
		}
	}

	if(1 == nsFlag) {
		ret = IMP_AI_EnableNs(&attr, NS_VERYHIGH);
		if(ret != 0) {
			printf("enable audio ns error.\n");
			IMP_LOG_INFO(TAG, "enable audio ns error.\n");
			return NULL;
		}
	}

	if(1 == agcFlag) {
		ret = IMP_AI_EnableAgc(&attr, agcConfig);
		if(ret != 0) {
			printf("enable audio agc error.\n");
			IMP_LOG_INFO(TAG, "enable audio agc error.\n");
			return NULL;
		}
	}

	while(1) {
		/* Step 6: get audio record frame. */

		ret = IMP_AI_PollingFrame(devID, chnID, 1000);
		if (ret != 0 ) {
			IMP_LOG_ERR(TAG, "Audio Polling Frame Data error\n");
		}
		IMPAudioFrame frm;
		ret = IMP_AI_GetFrame(devID, chnID, &frm, BLOCK);
		if(ret != 0) {
			IMP_LOG_ERR(TAG, "Audio Get Frame Data error\n");
			return NULL;
		}

		/* Step 7: Save the recording data to a file. */
		fwrite(frm.virAddr, 1, frm.len, record_file);

		/* Step 8: release the audio record frame. */
		ret = IMP_AI_ReleaseFrame(devID, chnID, &frm);
		if(ret != 0) {
			IMP_LOG_ERR(TAG, "Audio release frame data error\n");
			return NULL;
		}

		if(++record_num >= recordTime)
			break;
	}

	/* Disable Aec */
	ret = IMP_AI_DisableAec(devID, chnID);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "Audio enable aec failed\n");
		return NULL;
	}
	if(1 == hpfFlag) {
		ret = IMP_AI_DisableHpf();
		if(ret != 0) {
			printf("disable hpf error.\n");
			IMP_LOG_INFO(TAG, "enable audio hpf error.\n");
			return NULL;
		}
	}
	if(1 == nsFlag) {
		ret = IMP_AI_DisableNs();
		if(ret != 0) {
			printf("disable audio ns error.\n");
			IMP_LOG_INFO(TAG, "disable audio ns error.\n");
			return NULL;
		}
	}
	if(1 == agcFlag) {
		ret = IMP_AI_DisableAgc();
		if(ret != 0) {
			printf("disable audio agc error.\n");
			IMP_LOG_INFO(TAG, "disable audio agc error.\n");
			return NULL;
		}
	}

	/* Step 9: disable the audio channel. */
	ret = IMP_AI_DisableChn(devID, chnID);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "Audio channel disable error\n");
		return NULL;
	}

	/* Step 10: disable the audio devices. */
	ret = IMP_AI_Disable(devID);
	if(ret != 0) {
		IMP_LOG_ERR(TAG, "Audio device disable error\n");
		return NULL;
	}

	fclose(record_file);
	pthread_exit(0);
}

static void set_aiTest_param(TEST_ARGS *pTestArgs)
{
	if(NULL == pTestArgs) {
		printf("fun:%s,pTestArgs is empty.\n",__func__);
		return;
	}
	if(strcmp(pTestArgs->outFileName,"") != 0)
		strncpy(outFileName,pTestArgs->outFileName,MAX_FILE_NAME_LEN);

	if(pTestArgs->sampleRate > 0)
		sampleRate = pTestArgs->sampleRate;

	if(pTestArgs->frmNum > 0)
		frmNum = pTestArgs->frmNum;

	if(pTestArgs->numPerFrm > 0)
		numPerFrm = pTestArgs->numPerFrm;
	else
		numPerFrm = (sampleRate/100)*4;

	if(pTestArgs->num > 0)
		recordTime = (pTestArgs->num)*sampleRate/numPerFrm;
	else
		recordTime = 10*sampleRate/numPerFrm;

	if(pTestArgs->vol != 60)
		aiVol = pTestArgs->vol;

	if(pTestArgs->gain != 28)
		aiGain = pTestArgs->gain;

	if(pTestArgs->nsMode >= 0) {    /*set NS mode and flag*/
		nsMode = pTestArgs->nsMode;
		nsFlag = 1;
	}

	if(pTestArgs->hpfFlag != 0)
		hpfFlag = pTestArgs->hpfFlag;

	if(((pTestArgs->agcConfig).TargetLevelDbfs != -1)&&((pTestArgs->agcConfig).CompressionGaindB != -1)){
			agcConfig.TargetLevelDbfs = (pTestArgs->agcConfig).TargetLevelDbfs;
			agcConfig.CompressionGaindB = (pTestArgs->agcConfig).CompressionGaindB;
			agcFlag = 1;
	}

}

int main(int argc, char *argv[])
{
	int ret;

	ret = parse_param(argc,argv);
	if(1 == ret) {
		return 0;
	}
	if(ret < 0) {
		printf("[ERROR]:parse_param failed\n");
		return -1;
	} else {
		printf("[INFO]:parse_param Ok.\n");
	}
	set_aiTest_param(&testArgs);

	printf("[INFO]:outFileName = %s\n",outFileName);
	printf("[INFO]:sampleRate = %d\n",sampleRate);
	printf("[INFO]:frmNum = %d\n",frmNum);
	printf("[INFO]:numPerFrm = %d\n",numPerFrm);
	printf("[INFO]:aiVol = %d\n",aiVol);
	printf("[INFO]:aiGain = %d\n",aiGain);
	printf("[INFO]:audio record time is %ds\n",testArgs.num);

	if(1 == nsFlag) {
		printf("[INFO]:Ns mode is:%d\n",nsMode);
	}

	if(1 == hpfFlag) {
		printf("[INFO]:HPF is enabled.\n");
	}

	if(1 == agcFlag) {
		printf("[INFO]:agcConfig.TargetLevelDbfs = %d\n",agcConfig.TargetLevelDbfs);
		printf("[INFO]:agcConfig.CompressionGaindB = %d\n",agcConfig.CompressionGaindB);
	}

	printf("[INFO] Test 1: Start audio record test.\n");
	printf("[INFO]        : Can create the %s file.\n",outFileName);
	printf("[INFO]        : Please input any key to continue.\n");
	getchar();

	pthread_t record_thread_id;
	ret = pthread_create(&record_thread_id, NULL,ai_record_thread,NULL);
	if(ret != 0) {
		printf("[ERROR]:Create IMP_Audio_Record_Thread failed\n");
		return -1;
	}
	pthread_join(record_thread_id, NULL);

	printf("[INFO]:Finished record audio test\n");

	return 0;
}
